package com.binc.testspring.common.interceptor;

import com.binc.testspring.common.LogAuthAnnotation;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 第一个自定义拦截器
 *      这个个拦截器是用的  实现HandlerInterceptor 接口   +  自定义注解的方式实现的；
 *
 *     自定一注解一定要注册配置
 *
 *
 * preHandle
 * * 调用时间：Controller方法处理之前
 * * 执行顺序：链式Intercepter情况下，Intercepter按照声明的顺序一个接一个执行
 * * 若返回false，则中断执行，注意：不会进入afterCompletion
 *
 **
 * postHandle
 * * 调用前提：preHandle返回true
 * * 调用时间：Controller方法处理完之后，DispatcherServlet进行视图的渲染之前，也就是说在这个方法中你可以对ModelAndView进行操作
 * * 执行顺序：链式Intercepter情况下，Intercepter按照声明的顺序倒着执行。
 * * 备注：postHandle虽然post打头，但post、get方法都能处理
 *
 **
 * afterCompletion
 * * 调用前提：preHandle返回true
 * * 调用时间：DispatcherServlet进行视图的渲染之后
 * * 多用于清理资源
 */
public class BincInterceptor_first implements HandlerInterceptor {


    /*
        preHandle是请求执行前执行的，
        postHandler是请求结束执行的，
            但只有preHandle方法返回true的时候才会执行，
        afterCompletion是视图渲染完成后才执行，
            同样需要preHandle返回true，该方法通常用于清理资源等工作
     */



    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * boolean 值： 确定了拦截器其余两方法是否执行
         */
        // return true;
        // 如果不是映射到方法直接通过
        request.setAttribute("startTime", new Date().getTime());
        if (!(handler instanceof HandlerMethod)) {  //这是如果不是普通方法的话   就不拦截了   也可以换个写法    见下面被注释掉的代码
            return true;
        }

        //Spring boot 2.0对静态资源也进行了拦截，当拦截器拦截到请求之后，是静态资源的话，不拦截
        // if (handler instanceof ResourceHttpRequestHandler) {
        //     return true;
        // }

        System.out.println("TimeInterceptor 进入 Controller 某个方法之前");
         /*
        springboot2之后开始拦截静态资源了， 如果我们进行了 mvc的 addResourceHandlers()配置，那么如果访问这些静态资源的时候， 本拦截器方法中的handler形参 其实是一个ResourceHttpRequestHandler，
                如果强转成HandlerMethod 是要报错的(就会抛出【java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod】错误)；
                解决办法有两个；
                1 在拦截器那里排除静态资源的请求路径，也就是静态资源的访问不会被拦截到，也就走不到拦截器方法，也就没有强转什么事情了  （一劳永逸，推荐）
                2 拦截器配置不做调整，但是在拦截器方法上添加一个代码，判断一下handler instanceof 什么类型的；如果是heanlderMethod就继续执行，
                    如果是ResourceHttpRequestHandler类型 就跳过（return true），跳过拦截器的方法；
                方式2有个缺点：如果没添加一个拦截器的话，都得想着添加这个东西（不是很推荐）
        */
        System.out.println("Controller Name:"+((HandlerMethod)handler).getBean().getClass().getName());
        System.out.println("Controller Method Name:"+((HandlerMethod)handler).getMethod().getName());
        request.setAttribute("startTime", new Date().getTime());

        // ①:START 方法注解级拦截器
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 判断接口是否需要登录  （【自定义的注解，这个注解的作用就是在拦截器里判断拦截到的方法是否有标注这个注解，一旦标注了这个注解，我们就认为他是我们要拦截的目标方法；然后开始各种的校验等；】）
        LogAuthAnnotation myAnnotation =  method.getAnnotation(LogAuthAnnotation.class);
        // 如果方法上边看到了这个注解，我们认为他是需要认证的
        if (myAnnotation != null) {
            // 这写你拦截需要干的事儿，比如取缓存，SESSION，权限判断等
            System.out.println("===============BincInterceptor_first  拦截器执行=====================");
            return true;
        }
        return true;
    }



    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("TimeInterceptor 运行 Controller 某个方法时，方法抛出异常将不进入此方法");
        long start = (long) request.getAttribute("startTime");
        System.out.println("TimeInterceptor 处理时长为："+ (new Date().getTime() - start));

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("TimeInterceptor 完成 Controller 某个方法");
        long start = (long) request.getAttribute("startTime");
        System.out.println("TimeInterceptor 处理时长为："+ (new Date().getTime() - start));

    }
}
